/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "drivers/hisport.h"
#include <iostream>
#include <map>
#include <mc/exception.h>
#include <mutex>
#include <sstream>
#include <iomanip>

namespace DRIVER_HISPORT {

// 全局存储映射，模拟硬件内存
// 使用复合键 (bus_id, addr, offset) 来存储数据
struct MemoryKey {
    uint8_t  bus_id;
    uint32_t addr;
    uint32_t offset;

    bool operator<(const MemoryKey& other) const {
        if (bus_id != other.bus_id) {
            return bus_id < other.bus_id;
        }
        if (addr != other.addr) {
            return addr < other.addr;
        }
        return offset < other.offset;
    }
};

static std::map<MemoryKey, std::string> g_memory_map;
static std::mutex                       g_memory_mutex;

// 辅助函数：将字符串转换为十六进制格式
std::string to_hex_string(const std::string& data) {
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (unsigned char byte : data) {
        ss << std::setw(2) << static_cast<int>(byte) << " ";
    }
    return ss.str();
}

void Hisport::init(const HISPORT_INIT_S& init_data, std::string bus_name) {
    // 打桩实现：记录初始化参数
    std::cout << "Hisport打桩初始化: bus_name=" << bus_name
              << ", bus_num=" << int(init_data.bus_num)
              << ", reg_num=" << int(init_data.reg_num)
              << ", flag_num=" << int(init_data.flag_num)
              << ", send_reg_addr=" << int(init_data.send_reg_addr)
              << ", recv_reg_addr=" << int(init_data.recv_reg_addr)
              << ", flag_reg_addr=" << int(init_data.flag_reg_addr)
              << ", max_batch_len=" << int(init_data.max_batch_len)
              << ", max_data_len=" << init_data.max_data_len
              << ", max_offset_width=" << int(init_data.max_offset_width)
              << ", max_length_width=" << int(init_data.max_length_width) << std::endl;
}

void Hisport::lock() {
    // 打桩实现：模拟锁定总线
}

void Hisport::unlock() {
    // 打桩实现：模拟解锁总线
}

std::string Hisport::read(const HISPORT_DATA_S& read_data) {
    // 打桩实现：模拟读取操作
    // 参数验证
    validate_offset_width(read_data.offset_width);
    validate_data_width(read_data.data_width);

    std::lock_guard<std::mutex> lock(g_memory_mutex);

    // 构建内存键
    MemoryKey key{read_data.bus_id, read_data.addr, read_data.offset};

    // 从内存映射中读取数据
    auto it = g_memory_map.find(key);
    if (it != g_memory_map.end()) {
        std::string data = it->second;
        // 如果读取长度小于存储的数据长度，截取指定长度
        if (data.length() > read_data.rx_len) {
            data = data.substr(0, read_data.rx_len);
        }
        // 如果读取长度大于存储的数据长度，用默认值填充
        else if (data.length() < read_data.rx_len) {
            data.append(read_data.rx_len - data.length(), '\0');
        }

        return data;
    } else {
        // 如果地址不存在，返回默认数据
        std::string default_data(read_data.rx_len, '\0');
        return default_data;
    }
}

void Hisport::write(const HISPORT_DATA_S& write_data, std::string_view& data) {
    // 打桩实现：模拟写入操作
    // 参数验证
    validate_offset_width(write_data.offset_width);
    validate_data_width(write_data.data_width);

    std::lock_guard<std::mutex> lock(g_memory_mutex);

    // 构建内存键
    MemoryKey key{write_data.bus_id, write_data.addr, write_data.offset};

    // 将数据存储到内存映射中
    g_memory_map[key] = std::string(data.data(), data.size());

    // 返回成功
    return;
}

// 参数验证函数
void Hisport::validate_offset_width(uint8_t offset_width) {
    if (offset_width > 4) {
        MC_THROW(mc::invalid_arg_exception, "Offset width exceeds maximum value 4");
    }
}

void Hisport::validate_data_width(uint32_t data_width) {
    if (data_width == 0 || data_width > 1024) {
        MC_THROW(mc::invalid_arg_exception, "Data width is invalid");
    }
}

} // namespace DRIVER_HISPORT